home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 June: ROMin Holiday / ADC Developer CD (1992-06) (''ROMin Holiday'')_iso / Developer Connection - 06-1992.iso / Development Platforms / Apple II / Essentials / Technical.Notes / IIGS / TN.IIGS.071 < prev    next >
Encoding:
Text File  |  1991-11-15  |  15.5 KB  |  358 lines  |  [TEXT/pdos]

  1. Apple II
  2. Technical Notes
  3. _____________________________________________________________________________
  4.                                                   Developer Technical Support
  5.  
  6.  
  7. Apple IIgs
  8. #71:         DA Tips and Techniques
  9.  
  10. Revised by:  Dave "Mr. Tangent" Lyons                           December 1991
  11. Written by:  Dave Lyons                                         November 1989
  12.  
  13. This Technical Note presents tips and techniques for writing Desk 
  14. Accessories.
  15.  
  16. Changes since July 1991:  Added information on NDAs finding their own menu
  17. item IDs.
  18. _____________________________________________________________________________
  19.  
  20.  
  21. Classic Desk Accessory Tips and Techniques
  22.  
  23. Reading the Keyboard
  24.  
  25. For a CDA that runs only under GS/OS, the Console Driver is the best choice 
  26. for reading from the keyboard.  Other CDAs have two cases to deal with:  the 
  27. Event Manager may or may not be started.  The Text Tools can read the 
  28. keyboard in either case, but you should avoid using the Text Tools whenever 
  29. possible (see Apple IIgs Technical Note #69, The Ins and Outs of Slot 
  30. Arbitration).
  31.  
  32. You can call EMStatus to determine whether the Event Manager is started.  
  33. When it is, you can read keypresses by calling GetNextEvent.  When the Event 
  34. Manager is not started, you can read keys directly from the keyboard hardware 
  35. by waiting for bit 7 of location $E0C000 to turn on.  When it does, the lower 
  36. seven bits represent the key pressed.  Once you've detected a keypress, you 
  37. need to write to location $E0C010 to remove the keypress from the buffer.
  38.  
  39. Alternately, you can use IntSource (in the Miscellaneous Tools) to 
  40. temporarily disable keyboard interrupts and then read the keyboard hardware 
  41. directly.  Be sure to reactivate keyboard interrupts if, and only if, they 
  42. were previously enabled.
  43.  
  44. Just One Page of Stack Space
  45.  
  46. CDAs normally have only a single page of stack space available to them (256 
  47. bytes at $00/01xx).  Your CDA may or may not be able to allocate additional 
  48. stack space from bank 0 during execution.  The following code (written for 
  49. the MPW IIgs cross-assembler) shows a safe way to try to allocate more stack 
  50. space and to switch between stacks when the space is available.
  51.  
  52. If ProDOS 8 is active, your CDA cannot allocate additional space (and there 
  53. is no completely safe way to "borrow" bank 0 space from the ProDOS 8 
  54. application).
  55.  
  56.  
  57. HowMuchStack   gequ    $1000          ;try for 4K of stack space
  58.  
  59. start          phd
  60.                phb
  61.                phk
  62.                plb
  63.                pha                    ;Space for result
  64.                pha
  65.                PushLong #HowMuchStack
  66.                pha
  67.                _MMStartUp
  68.                pla
  69.                ora    #$0f00          ;OR in an arbitrary auxiliary ID
  70.                pha
  71.                PushWord #$C001        ;fixed, locked, use specified bank
  72.                PushLong #0            ;(specify bank 0)
  73.                _NewHandle
  74.                tsc
  75.                sta    theOldStack
  76.                bcs    NoStackSpace    ;still set from _NewHandle
  77.                tcd
  78.                lda    [1]
  79.                tcd
  80. ;               clc                    ;carry is already clear
  81.                adc    #HowMuchStack-1
  82. NoStackSpace   pha
  83.                ldx    #$fe
  84. keepStack      lda    >$000100,x
  85.                sta    stackImage,x
  86.                dex
  87.                dex
  88.                bpl    keepStack
  89.                pla
  90.                tcs
  91.                jsl    RealCDAentry     ;carry is clear if large stack 
  92. available
  93.                php
  94.                php
  95.                pla
  96.                sta    pRegister
  97.                sei
  98.                ldx    #$fe
  99. restoreStack   lda    stackImage,x
  100.                sta    >$000100,x
  101.                dex
  102.                dex
  103.                bpl    restoreStack
  104.                lda    theOldStack
  105.                tcs
  106.                lda    pRegister
  107.                pha
  108.                plp
  109.                plp
  110.                lda    1,s
  111.                ora    3,s
  112.                beq    noDispose
  113.                _DisposeHandle
  114.                bra    Exit
  115. noDispose      pla
  116.                pla
  117. Exit           plb
  118.                pld
  119.                rtl
  120. pRegister     ds 2
  121. theOldStack   ds 2
  122. stackImage    ds.b 256
  123.  
  124. When this routine calls RealCDAentry, the carry flag is set if no extra stack 
  125. space is available.  If the carry is clear, the additional stack space was 
  126. available and the direct-page register points to the bottom of that space.
  127.  
  128. RealCDAentry   bcs    smallStack            ;if c set, only 1 page of stack
  129.                                             ;is available
  130.                ...                          ; put something interesting here
  131.                rtl
  132.  
  133. smallStack     _SysBeep
  134.                rtl
  135.  
  136. Note that interrupts are disabled while the page-one stack is being restored; 
  137. they are reenabled (if they were originally enabled) only after the stack 
  138. pointer is safely back in page one.
  139.  
  140. Interrupts, Event Manager, Memory, and CDAs
  141.  
  142. Whether the Event Manager is active or not, the user hits Apple-Ctrl-Esc and 
  143. usually gets to the CDA menu.  It looks the same, but what happens internally 
  144. is different affects what happens when your CDA allocates memory.
  145.  
  146. When the Event Manager is active (as it normally is while the user is running 
  147. a Desktop application), hitting Apple-Ctrl-Esc posts a deskAcc event to the 
  148. event queue.  The CDA menu appears only when the application calls 
  149. GetNextEvent or EventAvail with the deskAcc bit enabled in the event mask.
  150.  
  151. So with the Event Manager active, the CDA menu and individual CDAs are 
  152. running in the "foreground"--no processor interrupt is being serviced, and 
  153. the foreground application is stuck inside the GetNextEvent or EventAvail 
  154. call.  The Memory Manager knows that no interrupt is in progress, so it will 
  155. happily compact and purge memory if necessary to carry out a memory 
  156. allocation request from your CDA.  This is just fine, since the foreground 
  157. application made a toolbox call--unlocked memory blocks are not guaranteed to 
  158. stay put.
  159.  
  160. When the Event Manager is not active, hitting Apple-Ctrl-Esc either enters 
  161. the CDA menu immediately (if the system Busy Flag is zero) or calls 
  162. SchAddTask so that the CDA menu appears during a the next DECBUSYFLG call 
  163. that brings the system Busy Flag down to zero.  If the CDA menu appears 
  164. during a DECBUSYFLG , normal memory compaction and purging are possible, just 
  165. like when the Event Manager is active.
  166.  
  167. But if the Busy Flag was zero when the user hit Apple-Ctrl-Esc, then the CDA 
  168. menu appears inside of the interrupt, and the foreground application is at an 
  169. unknown point where it may justifiably expect that unlocked memory blocks 
  170. will not move or be purged (see Apple IIgs Toolbox Reference, Volume 1, page 
  171. 12-5).  (Note that the Desk Manager does a tricky dance to allow additional 
  172. interrupts to occur, even though the Apple-Ctrl-Esc interrupt will not return 
  173. until the user chooses Quit from the CDA menu.  Normally interrupts cannot be 
  174. nested; the Desk Manager and AppleTalk are exceptions.)
  175.  
  176. The Memory Manager knows an interrupt is in progress, so CompactMem takes no 
  177. action and memory allocation requests do not cause unlocked memory blocks to 
  178. move and do not attempt to purge purgeable blocks to make room.  Memory 
  179. allocation requests will still normally succeed, but you will not be able to 
  180. allocate a block larger than the value returned by MaxBlock.
  181.  
  182. New Desk Accessory Tips and Techniques
  183.  
  184. An NDA Can Find its Menu Item ID
  185.  
  186. After the application has called FixAppleMenu, an NDA can look at its 
  187. menu item template (after the "\H" in the NDA header) to determine the 
  188. menu ID corresponding to the NDA's name in the Apple menu.  This is 
  189. sometimes useful to pass to OpenNDA (if the NDA has some way to open 
  190. itself), or to pass to a Menu Manager call.
  191.  
  192. Finding the menu item ID in the NDA's header is easy if the NDA is 
  193. written in assembly.  In a high-level language it may be harder (if you 
  194. don't have direct access to your NDA's header, you need to find it on 
  195. the fly and scan for the "\H").
  196.  
  197. NDAs Continue to Get Command- Keystrokes
  198.  
  199. Previous versions of this Note said that NDAs are not guaranteed to receive 
  200. key-down events with the Command key down, because System Software might be 
  201. revised to pass such keys directly to the current application instead.
  202.  
  203. In light of the reaction of several interested parties, that warning is being 
  204. withdrawn.  When an NDA is in front, it has first crack at key-down events, 
  205. even when the Command key is down.
  206.  
  207. There is currently no way for an NDA to accept some keystrokes and pass 
  208. others along to applications, but if your NDA does not want any keystroke 
  209. events, turn off the corresponding eventMask bits in the NDA header (this 
  210. allows the application to receive keystrokes while your NDA window is in 
  211. front).
  212.  
  213. You may want to support the standard Close key equivalent, Command-W.  When 
  214. your NDA's action routine receives an Command-W (or Command-w) keyDown or 
  215. autoKey event, you can call CloseNDAByWinPtr with your own window pointer.  
  216. This causes a call to your NDA's Close routine within the call to your Action 
  217. routine--if your code has no problem with this, neither does the Desk 
  218. Manager.
  219.  
  220. Note:    System 6.0 handles Command-W automatically when a system window is
  221.          in front.  It calls CloseNDAbyWinPtr without letting the NDA or the
  222.          application see the Command-W.
  223.  
  224.  
  225.  
  226. Calling InstallNDA From Within an NDA
  227.  
  228. It is possible to write an NDA that installs other NDAs.  However, with 
  229. System Software 5.0 and later, InstallNDA returns an error when called from 
  230. an NDA.  When your NDA has control because the Desk Manager called one of 
  231. your NDA's entry points, the Desk Manager's data structures are already in 
  232. use, so InstallNDA is unable to modify them.
  233.  
  234. The solution is to use SchAddTask in the Scheduler to postpone the InstallNDA 
  235. call until the system is not busy.  Remember that the Bank and Direct Page 
  236. registers are not defined when your scheduled task is executed.
  237.  
  238. Processing mouseUp Events
  239.  
  240. When an NDA's action routine receives a mouseUp event, it is not always safe 
  241. for the NDA to draw in its window.
  242.  
  243. For example, when the user drags an NDA window, the NDA receives the mouseUp 
  244. before the window is actually moved, and before DragWindow erases the outline 
  245. of the new window position, which may overlap the window's content.  In 
  246. addition, when the user chooses a menu item, the front NDA receives the 
  247. mouseUp before the menu's image is removed, and the image may overlap the 
  248. NDA's window.  In either case, drawing in the window makes a mess.
  249.  
  250. The solution is to avoid drawing in direct response to a mouseUp.  Instead, 
  251. invalidate part of the window to force an update event to happen later.
  252.  
  253. NDAs Can Have Resource Forks
  254.  
  255. Following is the recommended way for a New Desk Accessory to use its file's 
  256. resource fork.
  257.  
  258. In the NDA's Open routine, do the following:
  259.  
  260.     1.    Call GetCurResourceApp and keep the result.
  261.     2.    If the NDA does not already know its Memory Manager user ID, call 
  262.           MMStartUp to get it.
  263.     3.    Call ResourceStartUp using the NDA's user ID.
  264.     4.    Call the Loader function LGetPathname2 with the NDA's user ID (and 
  265.           a fileNumber of $0001) to get a pointer to the NDA's pathname.  
  266.           (The result is a pointer to a class-one GS/OS string.)
  267.     5.    Use GetLevel to get the current file level, then use SetLevel to 
  268.           set it to zero.  This helps protect your resource fork from being 
  269.           closed accidentally.
  270.     6.    Use GetSysPrefs to get the current OS preferences, then use 
  271.           SetSysPrefs to ensure that the user is prompted, if necessary, to 
  272.           insert the disk containing your resource fork.  (To compute the new 
  273.           preferences word, take the current one, AND it with $1FFF, and ORA 
  274.           it with $8000.  This tells GS/OS to deal with volume-not-found 
  275.           conditions by putting up a please-insert-disk dialog with an OK 
  276.           button and a Cancel button.)
  277.     7.    Call OpenResourceFile using the result from LGetPathname2.  Save 
  278.           the returned fileID--you need it when closing the file.  (Be 
  279.           prepared to deal with an error, such as $0045, Volume Not Found.)
  280.     8.    Use SetSysPrefs to restore the OS preferences saved in step six.
  281.     9.    Use SetLevel to restore the file level to its old value (saved in 
  282.           step five).
  283.     10.   Call SetCurResourceApp with the old value saved in step one.
  284.  
  285. In the NDA's action routine, no special calls are necessary--the Desk Manager 
  286. calls SetCurResourceApp automatically before calling your action routine, so 
  287. your NDA's own resource search path is already in effect.
  288.  
  289. Run queue routines and NDA installs with AddToRunQ are treated the same 
  290. way--the NDA's resource search path is automatically in effect when the run 
  291. queue routine is called.
  292.  
  293. In the NDA's Close routine, do the following:
  294.  
  295. 1.    Call CloseResourceFile with the fileID that was returned when you 
  296.       opened it.
  297. 2.    Call ResourceShutDown with no parameters (the last version of this Note 
  298.       incorrectly said to pass the NDA's User ID--oops).
  299.  
  300.  
  301. NDAs Must Be Careful Handling Modal Windows
  302.  
  303. If your NDA uses its resource fork and calls TaskMaster with a restricted 
  304. wmTaskMask to produce a modal window, you must be careful not to allow 
  305. TaskMaster to update the contents of any application windows that happen to 
  306. need updating.
  307.  
  308. The problem is that an application window's wContDraw routine can reasonably 
  309. assume that the current Resource Manager search path is the application's, 
  310. but TaskMaster does not take any special steps to set it.  When the 
  311. content-draw routine draws controls which were created from resources which 
  312. are not presently in the resource search path, the system may crash.
  313.  
  314. If your NDA does not start up the Resource Manager, the Desk Manager is 
  315. unable to SetCurResourceApp to your NDA, so the application's search path is 
  316. still in effect--no problem.  But if your NDA does start the Resource 
  317. Manager, you have to be careful not to cause application routines to be 
  318. called.
  319.  
  320. Avoid Hard-Coding Your Pathname
  321.  
  322. If your NDA needs to know its own pathname or the pathname of the directory 
  323. it's in, call LGetPathname or LGetPathname2 using your User ID.  This is a 
  324. better method than hard-coding "*:System:Desk.Accs:MyDAName" because the user 
  325. may change your DA's file name or use a utility to install it from some 
  326. non-standard directory.
  327.  
  328. Avoid Extra GetNewID calls
  329.  
  330. Normally there is no reason for a Desk Accessory to call GetNewID.  When you 
  331. can, just call MMStartUp to find your own User ID, and use that.  You can 
  332. freely use all the auxiliary IDs derived from your main ID (MMStartUp+$0100, 
  333. MMStartUp+$0200, ..., MMStartUp+$0F00).
  334.  
  335. By not calling GetNewID, you conserve the limited supply of IDs (255 of in 
  336. the $50xx range for Desk Accessories), and you make life easier for people 
  337. trying to debug their systems, since all your allocated memory can be readily 
  338. identified.
  339.  
  340. Open is Not Called if NDA is Already Open
  341.  
  342. Your NDA's Open routine does not get called if the user chooses the NDA from 
  343. the Apple menu while the NDA is already open.  In this case, the Desk Manager 
  344. simply calls SelectWindow on your existing window.
  345.  
  346. There is no need to include code in your Open routine to check if your window 
  347. is already open, and to call SelectWindow if it is.
  348.  
  349.  
  350. Further Reference
  351. _____________________________________________________________________________
  352.   o   Apple IIgs Toolbox Reference, Volumes 1-3
  353.   o   GS/OS Reference
  354.   o   Apple IIgs Hardware Reference
  355.   o   Apple IIgs Technical Note #53, Desk Accessories and Tools
  356.   o   Apple IIGS Technical Note #57, The Memory Manager and Interrupts
  357.   o   Apple IIgs Technical Note #69, The Ins and Outs of Slot Arbitration
  358.